package utils

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"bsm/logger"

	ole "github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
)

type Operation struct {
	OpType    string
	Arguments []interface{}
}

type ExcelPdfConverterOLE struct {
	FileInPath      string
	FileOutPath     string
	ApplicationName string
	WorkspaceName   string
	Visible         bool
	DisplayAlerts   int
	OpenFileOp      Operation
	ExportOp        Operation
	CloseOp         Operation
	QuitOp          Operation
	// 未来可能添加状态字段，如转换计数、错误记录等
	conversionCount int
	lastError       error
}

type DomConvertObject struct {
	Application *ole.IDispatch
	Workbooks   *ole.IDispatch
	Workbook    *ole.IDispatch
}

// 使用指针接收者 - 因为可能修改状态且避免复制
func (handler *ExcelPdfConverterOLE) Convert() (string, error) {
	ole.CoInitialize(0)
	defer ole.CoUninitialize()

	// 可以更新状态
	handler.conversionCount++
	handler.lastError = nil

	logger.WithFields(map[string]interface{}{
		"layer":     "utils",
		"operation": "Convert",
	}).Info("开始打开OLE应用程序")

	dom, err := handler.Open()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Convert",
			"error":     err.Error(),
		}).Error("打开OLE应用程序失败")
		handler.lastError = err
		return handler.FileOutPath, fmt.Errorf("打开应用程序失败: %v", err)
	}
	defer handler.cleanup(dom)

	// log.Printf("输入文件: %s, 输出文件: %s", handler.FileInPath, handler.FileOutPath)
	logger.WithFields(map[string]interface{}{
		"layer":     "utils",
		"operation": "Convert",
	}).Info("开始OLE导出PDF文件")

	if err := handler.Export(dom); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Convert",
			"error":     err.Error(),
		}).Error("OLE导出PDF文件失败")
		handler.lastError = err
		return handler.FileOutPath, fmt.Errorf("导出失败: %v", err)
	}

	logger.WithFields(map[string]interface{}{
		"layer":     "utils",
		"operation": "Convert",
	}).Info("OLE导出PDF文件完成")

	if err := handler.Close(dom); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Convert",
			"error":     err.Error(),
		}).Error("OLE关闭文件失败")
		handler.lastError = err
		// return handler.FileOutPath, fmt.Errorf("关闭文件失败: %v", err)
	}
	logger.WithFields(map[string]interface{}{
		"layer":     "utils",
		"operation": "Convert",
	}).Info("OLE关闭文件完成")

	if err := handler.Quit(dom); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Convert",
			"error":     err.Error(),
		}).Error("OLE退出应用程序失败")
		handler.lastError = err
		return handler.FileOutPath, fmt.Errorf("退出应用程序失败: %v", err)
	}
	logger.WithFields(map[string]interface{}{
		"layer":     "utils",
		"operation": "Convert",
	}).Info("OLE退出应用程序完成")

	return handler.FileOutPath, nil
}

// 指针接收者 - 即使现在不修改状态，也为未来扩展留空间
func (handler *ExcelPdfConverterOLE) Open() (DomConvertObject, error) {
	var dom DomConvertObject

	unknown, err := oleutil.CreateObject(handler.ApplicationName)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Open",
			"error":     err.Error(),
		}).Error("OLE创建COM对象失败")
		handler.lastError = err
		return dom, fmt.Errorf("创建COM对象失败: %v", err)
	}

	dom.Application, err = unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Open",
			"error":     err.Error(),
		}).Error("OLE获取应用程序接口失败")
		handler.lastError = err
		return dom, fmt.Errorf("获取应用程序接口失败: %v", err)
	}

	oleutil.PutProperty(dom.Application, "Visible", handler.Visible)
	oleutil.PutProperty(dom.Application, "DisplayAlerts", handler.DisplayAlerts)

	workspace, err := oleutil.GetProperty(dom.Application, handler.WorkspaceName)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Open",
			"error":     err.Error(),
		}).Error("OLE获取工作空间失败")
		handler.lastError = err
		return dom, fmt.Errorf("获取工作空间失败: %v", err)
	}
	dom.Workbooks = workspace.ToIDispatch()

	file, err := oleutil.CallMethod(dom.Workbooks, handler.OpenFileOp.OpType, handler.OpenFileOp.Arguments...)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Open",
			"error":     err.Error(),
		}).Error("OLE打开文件失败")
		handler.lastError = err
		dom.Workbooks.Release()
		dom.Application.Release()
		return dom, fmt.Errorf("打开文件失败: %v", err)
	}
	dom.Workbook = file.ToIDispatch()

	return dom, nil
}

// 指针接收者 - 保持一致
func (handler *ExcelPdfConverterOLE) Export(dom DomConvertObject) error {
	_, err := oleutil.CallMethod(dom.Workbook, handler.ExportOp.OpType, handler.ExportOp.Arguments...)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Export",
			"error":     err.Error(),
		}).Error("OLE导出PDF文件失败")
		handler.lastError = err
		return fmt.Errorf("导出为PDF失败: %v", err)
	}
	return nil
}

func (handler *ExcelPdfConverterOLE) Close(dom DomConvertObject) error {
	var err error

	_, err = oleutil.CallMethod(dom.Workbooks, handler.CloseOp.OpType)

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "utils",
			"operation": "Close",
			"error":     err.Error(),
		}).Error("OLE关闭文件失败")
		handler.lastError = err
		return fmt.Errorf("关闭文件失败: %v", err)
	}
	return nil
}

func (handler *ExcelPdfConverterOLE) Quit(dom DomConvertObject) error {
	_, err := oleutil.CallMethod(dom.Application, handler.QuitOp.OpType, handler.QuitOp.Arguments...)
	if err != nil {
		return fmt.Errorf("退出应用程序失败: %v", err)
	}
	return nil
}

// 指针接收者 - 清理可能涉及状态修改
func (handler *ExcelPdfConverterOLE) cleanup(dom DomConvertObject) {
	if dom.Workbook != nil {
		dom.Workbook.Release()
	}
	if dom.Workbooks != nil {
		dom.Workbooks.Release()
	}
	if dom.Application != nil {
		dom.Application.Release()
	}

	// 可以添加状态清理
	handler.lastError = nil
}

// 新增：获取状态信息的方法（需要指针接收者）
func (handler *ExcelPdfConverterOLE) GetConversionCount() int {
	return handler.conversionCount
}

func (handler *ExcelPdfConverterOLE) GetLastError() error {
	return handler.lastError
}

func (handler *ExcelPdfConverterOLE) Reset() {
	handler.conversionCount = 0
	handler.lastError = nil
}

// 工具函数 - 不需要接收者，可以作为包级函数
func NewExcelPdfConverterOLE(fileInputPath string) *ExcelPdfConverterOLE {
	// 生成输出路径
	fileOutputDir := filepath.Join(os.TempDir(), "excel_pdf")
	os.MkdirAll(fileOutputDir, 0755)
	baseName := strings.TrimSuffix(filepath.Base(fileInputPath), filepath.Ext(fileInputPath))
	fileOutputPath := filepath.Join(fileOutputDir, baseName+".pdf")

	openArgs := []interface{}{fileInputPath, false, true}
	exportArgs := []interface{}{0, fileOutputPath}
	closeArgs := []interface{}{false}
	quitArgs := []interface{}{}

	return &ExcelPdfConverterOLE{
		FileInPath:      fileInputPath,
		FileOutPath:     fileOutputPath,
		ApplicationName: "Excel.Application",
		WorkspaceName:   "Workbooks",
		Visible:         false,
		DisplayAlerts:   0,
		OpenFileOp: Operation{
			OpType:    "Open",
			Arguments: openArgs,
		},
		ExportOp: Operation{
			OpType:    "ExportAsFixedFormat",
			Arguments: exportArgs,
		},
		CloseOp: Operation{
			OpType:    "Close",
			Arguments: closeArgs,
		},
		QuitOp: Operation{
			OpType:    "Quit",
			Arguments: quitArgs,
		},
	}
}
